home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / sys5 / iscwmpst.z / iscwmpst / tcp / isc-src / util / misc / qth.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-29  |  9.6 KB  |  380 lines

  1. /* qth: qth, locator, distance, course computations */
  2.  
  3. static char sccsid[] = "@(#) qth.c   1.7   87/09/13 19:54:50";
  4.  
  5. #include <ctype.h>
  6. #include <math.h>
  7. #include <string.h>
  8.  
  9. #define MYBREITE  (49l * 3600l + 1l * 60l + 15l)
  10. #define MYLAENGE -( 8l * 3600l + 22l * 60l + 30l)
  11. #define RADIUS   6370.0
  12.  
  13. static char **argv;
  14. static int argc;
  15.  
  16. /*---------------------------------------------------------------------------*/
  17.  
  18. static void usage()
  19. {
  20.   extern void exit();
  21.  
  22.   printf("usage:    qth <place> [<place>]\n");
  23.   printf("              <place> ::= <locator>\n");
  24.   printf("              <place> ::= <grd> [<min> [<sec>]] east|west\n");
  25.   printf("                          <grd> [<min> [<sec>]] north|south\n");
  26.   printf("\n");
  27.   printf("examples: qth jn48kp\n");
  28.   printf("          qth ei25e\n");
  29.   printf("          qth 8 53 28 east 48 38 33 north\n");
  30.   printf("          qth jn48aa 9 east 48 30 north\n");
  31.   exit(1);
  32. }
  33.  
  34. /*---------------------------------------------------------------------------*/
  35.  
  36. static double safe_acos(a)
  37. double a;
  38. {
  39.   if (a >=  1.0) return 0;
  40.   if (a <= -1.0) return M_PI;
  41.   return acos(a);
  42. }
  43.  
  44. /*---------------------------------------------------------------------------*/
  45.  
  46. static double norm_course(a)
  47. double a;
  48. {
  49.   while (a <    0.0) a += 360.0;
  50.   while (a >= 360.0) a -= 360.0;
  51.   return a;
  52. }
  53.  
  54. /*---------------------------------------------------------------------------*/
  55.  
  56. static long centervalue(value, center, period)
  57. long value, center, period;
  58. {
  59.   long range;
  60.  
  61.   range = period / 2;
  62.   while (value > center + range) value -= period;
  63.   while (value < center - range) value += period;
  64.   return value;
  65. }
  66.  
  67. /*---------------------------------------------------------------------------*/
  68.  
  69. static void sec_to_loc(laenge, breite, loc)
  70. long laenge, breite;
  71. char *loc;
  72. {
  73.   laenge = 180 * 3600l - laenge;
  74.   breite =  90 * 3600l + breite;
  75.   *loc++ = laenge / 72000 + 'A';   laenge = laenge % 72000;
  76.   *loc++ = breite / 36000 + 'A';   breite = breite % 36000;
  77.   *loc++ = laenge /  7200 + '0';   laenge = laenge %  7200;
  78.   *loc++ = breite /  3600 + '0';   breite = breite %  3600;
  79.   *loc++ = laenge /   300 + 'A';
  80.   *loc++ = breite /   150 + 'A';
  81.   *loc   =                  '\0';
  82. }
  83.  
  84. /*---------------------------------------------------------------------------*/
  85.  
  86. static void sec_to_qra(laenge, breite, qra)
  87. long laenge, breite;
  88. char *qra;
  89. {
  90.   long z;
  91.   static char table[] = "fedgjchab";
  92.  
  93.   laenge = -laenge;
  94.   while (laenge < 0) laenge += 26 * 7200l;
  95.   breite = breite - 40 * 3600l;
  96.   while (breite < 0) breite += 26 * 3600l;
  97.   *qra++ = (laenge / 7200) % 26 + 'A';   laenge = laenge % 7200;
  98.   *qra++ = (breite / 3600) % 26 + 'A';   breite = breite % 3600;
  99.   z  = (laenge / 720) + 71;   laenge = laenge % 720;
  100.   z -= (breite / 450) * 10;   breite = breite % 450;
  101.   *qra++ = z / 10 + '0';
  102.   *qra++ = z % 10 + '0';
  103.   *qra++ = table[laenge / 240 + (breite / 150) * 3];
  104.   *qra   = '\0';
  105. }
  106.  
  107. /*---------------------------------------------------------------------------*/
  108.  
  109. static void loc_to_sec(loc, laenge, breite)
  110. char *loc;
  111. long *laenge, *breite;
  112. {
  113.  
  114.   char *p;
  115.  
  116.   for (p=loc; *p; p++)
  117.     if (*p >= 'a' && *p <= 'z') *p -= 32;
  118.  
  119.   if (loc[0] < 'A' || loc[0] > 'R' ||
  120.       loc[1] < 'A' || loc[1] > 'R' ||
  121.       loc[2] < '0' || loc[2] > '9' ||
  122.       loc[3] < '0' || loc[3] > '9' ||
  123.       loc[4] < 'A' || loc[4] > 'X' ||
  124.       loc[5] < 'A' || loc[5] > 'X' ||
  125.       loc[6]) usage();
  126.  
  127.   *laenge =  180 * 3600l
  128.             - 20 * 3600l * (loc[0] - 'A')
  129.             -  2 * 3600l * (loc[2] - '0')
  130.             -  5 *   60l * (loc[4] - 'A')
  131.             -       150l;
  132.  
  133.   *breite = - 90 * 3600l
  134.             + 10 * 3600l * (loc[1] - 'A')
  135.             +      3600l * (loc[3] - '0')
  136.             +       150l * (loc[5] - 'A')
  137.             +        75l;
  138. }
  139.  
  140. /*---------------------------------------------------------------------------*/
  141.  
  142. static void qra_to_sec(qra, laenge, breite)
  143. char *qra;
  144. long *laenge, *breite;
  145. {
  146.   char *p;
  147.   long z;
  148.   static ltab[] = {240l, 480l, 480l, 480l, 240l, 0l,   0l,   0l, 0l, 240l};
  149.   static btab[] = {300l, 300l, 150l,   0l,   0l, 0l, 150l, 300l, 0l, 150l};
  150.  
  151.   for (p=qra; *p; p++)
  152.     if (*p >= 'a' && *p <= 'z') *p -= 32;
  153.  
  154.   if (qra[0] < 'A' || qra[0] > 'Z' ||
  155.       qra[1] < 'A' || qra[1] > 'Z' ||
  156.       qra[2] < '0' || qra[2] > '8' ||
  157.       qra[3] < '0' || qra[3] > '9' ||
  158.       qra[4] < 'A' || qra[4] > 'J' || qra[4] == 'I' ||
  159.       qra[5]) usage();
  160.  
  161.   z = 10 * (qra[2] - '0') + qra[3] - '0';
  162.   if (z < 1 || z > 80) usage();
  163.  
  164.   *laenge = - (qra[0] - 'A') * 7200l
  165.             - (z - 1) % 10 * 720l
  166.             - ltab[qra[4] - 'A']
  167.             - 120l;
  168.  
  169.   *breite =   40 * 3600l
  170.             + (qra[1] - 'A') * 3600l
  171.             + (7 - (z - 1) / 10) * 450l
  172.             + btab[qra[4] - 'A']
  173.             + 75l;
  174.   *laenge = centervalue(*laenge, MYLAENGE, 26 * 7200l);
  175.   *breite = centervalue(*breite, MYBREITE, 26 * 3600l);
  176. }
  177.  
  178. /*---------------------------------------------------------------------------*/
  179.  
  180. static char *course_name(a)
  181. double a;
  182. {
  183.   if (a <=  11.25) return "North";
  184.   if (a <=  33.75) return "North-North-East";
  185.   if (a <=  56.25) return "North-East";
  186.   if (a <=  78.75) return "East-North-East";
  187.   if (a <= 101.25) return "East";
  188.   if (a <= 123.75) return "East-South-East";
  189.   if (a <= 146.25) return "South-East";
  190.   if (a <= 168.75) return "South-South-East";
  191.   if (a <= 191.25) return "South";
  192.   if (a <= 213.75) return "South-South-West";
  193.   if (a <= 236.25) return "South-West";
  194.   if (a <= 258.75) return "West-South-West";
  195.   if (a <= 281.25) return "West";
  196.   if (a <= 303.75) return "West-North-West";
  197.   if (a <= 326.25) return "North-West";
  198.   if (a <= 348.75) return "North-North-West";
  199.   if (a <= 371.25) return "North";
  200.   return "???";
  201. }
  202.  
  203. /*---------------------------------------------------------------------------*/
  204.  
  205. static int get_int(s, lower, upper)
  206. char *s;
  207. int lower, upper;
  208. {
  209.   int i;
  210.  
  211.   if (!sscanf(s, "%d", &i)) usage();
  212.   if (i < lower || i > upper) usage();
  213.   return i;
  214. }
  215.  
  216. /*---------------------------------------------------------------------------*/
  217.  
  218. static void print_qth(prompt, laenge, breite, loc, qra)
  219. char *prompt;
  220. long laenge, breite;
  221. char *loc, *qra;
  222. {
  223.   char *pl, *pb;
  224.  
  225.   if (laenge < 0) { pl = "East"; laenge = -laenge; }
  226.   else              pl = "West";
  227.   if (breite < 0) { pb = "South"; breite = -breite; }
  228.   else              pb = "North";
  229.   printf("%s%3ld %2ld' %2ld\" %s  %3ld %2ld' %2ld\" %s  -->  %s = %s\n",
  230.          prompt,
  231.          laenge / 3600,
  232.          laenge / 60 % 60,
  233.          laenge % 60,
  234.          pl,
  235.          breite / 3600,
  236.          breite / 60 % 60,
  237.          breite % 60,
  238.          pb,
  239.          loc,
  240.          qra);
  241. }
  242.  
  243. /*---------------------------------------------------------------------------*/
  244.  
  245. static int parse_arg(laenge, breite)
  246. long *laenge, *breite;
  247. {
  248.   int c;
  249.  
  250.   if (! *argv) return -1;
  251.  
  252.   if (isalpha(*argv[0])) {
  253.     switch (strlen(*argv)) {
  254.     case 5:
  255.       qra_to_sec(*argv, laenge, breite);
  256.       break;
  257.     case 6:
  258.       loc_to_sec(*argv, laenge, breite);
  259.       break;
  260.     default:
  261.       usage();
  262.       break;
  263.     }
  264.     argv++;
  265.     return 0;
  266.   }
  267.  
  268.   *laenge = 3600l * get_int(*argv, 0, 179);
  269.   argv++;
  270.   if (*argv && isdigit(*argv[0])) {
  271.     *laenge += 60l * get_int(*argv, 0, 59);
  272.     argv++;
  273.     if (*argv && isdigit(*argv[0])) {
  274.       *laenge += get_int(*argv, 0, 59);
  275.       argv++;
  276.     }
  277.   }
  278.   if (! *argv) usage();
  279.   c = *argv[0];
  280.   if (c == 'E' || c == 'e') *laenge = - *laenge;
  281.   else if (c != 'W' && c != 'w') usage();
  282.   argv++;
  283.  
  284.   if (! *argv) usage();
  285.   *breite = 3600l * get_int(*argv, 0, 89);
  286.   argv++;
  287.   if (*argv && isdigit(*argv[0])) {
  288.     *breite += 60l * get_int(*argv, 0, 59);
  289.     argv++;
  290.     if (*argv && isdigit(*argv[0])) {
  291.       *breite += get_int(*argv, 0, 59);
  292.       argv++;
  293.     }
  294.   }
  295.   if (! *argv) usage();
  296.   c = *argv[0];
  297.   if (c == 'S' || c == 's') *breite = - *breite;
  298.   else if (c != 'N' && c != 'n') usage();
  299.   argv++;
  300.  
  301.   return 0;
  302. }
  303.  
  304. /*---------------------------------------------------------------------------*/
  305.  
  306. main(pargc, pargv)
  307. int pargc;
  308. char **pargv;
  309. {
  310.  
  311.   char loc1[7], loc2[7];
  312.   char qra1[6], qra2[6];
  313.   double a1, a2;
  314.   double b1, b2;
  315.   double e;
  316.   double l1, l2;
  317.   int two_is_me;
  318.   long breite1, breite2;
  319.   long laenge1, laenge2;
  320.  
  321.   argc = --pargc;
  322.   argv = ++pargv;
  323.  
  324.   if (parse_arg(&laenge1, &breite1)) usage();
  325.   sec_to_loc(laenge1, breite1, loc1);
  326.   sec_to_qra(laenge1, breite1, qra1);
  327.  
  328.   two_is_me = 0;
  329.   if (parse_arg(&laenge2, &breite2)) {
  330.     laenge2 = MYLAENGE;
  331.     breite2 = MYBREITE;
  332.     two_is_me = 1;
  333.   }
  334.   sec_to_loc(laenge2, breite2, loc2);
  335.   sec_to_qra(laenge2, breite2, qra2);
  336.  
  337.   if (*argv) usage();
  338.  
  339.   l1 = laenge1 / 648000.0 * M_PI;
  340.   l2 = laenge2 / 648000.0 * M_PI;
  341.   b1 = breite1 / 648000.0 * M_PI;
  342.   b2 = breite2 / 648000.0 * M_PI;
  343.  
  344.   e = safe_acos(sin(b1) * sin(b2) + cos(b1) * cos(b2) * cos(l2-l1));
  345.  
  346.   if (!e)
  347.     print_qth("qth:  ", laenge1, breite1, loc1, qra1);
  348.   else {
  349.     if (two_is_me) {
  350.       print_qth("your qth:       ", laenge1, breite1, loc1, qra1);
  351.       print_qth(" my  qth:       ", laenge2, breite2, loc2, qra2);
  352.     }
  353.     else {
  354.       print_qth("1st  qth:       ", laenge1, breite1, loc1, qra1);
  355.       print_qth("2nd  qth:       ", laenge2, breite2, loc2, qra2);
  356.     }
  357.  
  358.     printf("distance:       %.1f km\n", e * RADIUS);
  359.  
  360.     a1 = safe_acos((sin(b2) - sin(b1) * cos(e)) / sin(e) / cos(b1)) / M_PI * 180.0;
  361.     a2 = safe_acos((sin(b1) - sin(b2) * cos(e)) / sin(e) / cos(b2)) / M_PI * 180.0;
  362.  
  363.     if (l2 > l1) a1 = 360.0 - a1;
  364.     if (l1 > l2) a2 = 360.0 - a2;
  365.  
  366.     a1 = norm_course(a1);
  367.     a2 = norm_course(a2);
  368.  
  369.     if (two_is_me) {
  370.       printf("course you->me: %3.0f (%s)\n", a1, course_name(a1));
  371.       printf("course me->you: %3.0f (%s)\n", a2, course_name(a2));
  372.     } else {
  373.       printf("course 1 --> 2: %3.0f (%s)\n", a1, course_name(a1));
  374.       printf("course 2 --> 1: %3.0f (%s)\n", a2, course_name(a2));
  375.     }
  376.   }
  377.   return 0;
  378. }
  379.  
  380.